{*******************************************************}
{                                                       }
{       DevOnRails                                      }
{                                                       }
{       Copyright (C) 2012 AllanGomes                   }
{                                                       }
{*******************************************************}

unit Rails.Vcl.Components;

interface

uses
  System.Classes, Vcl.Themes, Vcl.StdCtrls, Vcl.ExtCtrls, System.Generics.Collections,
  Vcl.Controls, Rails.Vcl.Events, Vcl.Mask, Rails.ActiveRecord.Attributes,
  Vcl.Grids;

type
{$REGION 'TValidatesEventsRails'}
  TValidatesEventsRails = class(TValidatesEvents)
  public
    class procedure LoadSettingsCharCase(Sender: TObject);
    class procedure Bank_Change(Sender: TObject; Precision, Decimals:Integer; Validation: TRailsValidations); reintroduce;
    class procedure Bank_KeyPress(Sender: TObject; var Key: Char; Precision: Integer; Validation: TRailsValidations); reintroduce;
    class procedure Bank_KeyUp(Sender: TObject; Validation: TRailsValidations); reintroduce;
    class procedure TabOnEnter_KeyPress(Sender: TObject; var Key: Char); reintroduce;
    class procedure Money_Enter(Sender: TObject; Validation: TRailsValidations); reintroduce;
    class procedure Money_Exit(Sender: TObject; Validation: TRailsValidations; Precision, Decimals:Integer; ShowCurrency: Boolean = True); reintroduce;
    class procedure Money_KeyPress(Sender: TObject; var Key: Char; SelText: string; Precision, Decimals:Integer; Validation: TRailsValidations); reintroduce;
    class procedure Positive_Exit(Sender: TObject; Validation: TRailsValidations); reintroduce;
  end;
{$ENDREGION}

{$REGION 'TRailsEdit'}
  TRailsEdit = class(TMaskEdit)
  private
    FTabOnEnter: Boolean;
    FValidations: TRailsValidations;
    FPrecision: Integer;
    FDecimals: Integer;
    FLabelTitle: TCustomLabel;
    OldText, OldCaption: string;
    FIsDecimal: Boolean;
    procedure SetValidations(const Value: TRailsValidations);
    procedure setLabelTitle(const Value: TCustomLabel);
    procedure PassWord_Enter; virtual;
    procedure PassWord_Exit; virtual;
    procedure setIsDecimal(const Value: Boolean);
  protected
    procedure DoEnter; override;
    procedure DoExit; override;
    procedure KeyPress(var Key: Char); override;
    procedure KeyUp(var Key: Word; Shift: TShiftState); override;
    procedure Change; override;
  public
    property IsDecimal: Boolean read FIsDecimal write setIsDecimal;
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property LabelTitle: TCustomLabel read FLabelTitle write setLabelTitle;
    property Precision: Integer read FPrecision write FPrecision;
    property Decimals: Integer read FDecimals write FDecimals;
    property TabOnEnter: Boolean read FTabOnEnter write FTabOnEnter;
    property Validations: TRailsValidations read FValidations write SetValidations;
  end;
{$ENDREGION}

{$REGION 'TRailsComboBox'}
  TRailsComboBox = class(TComboBox)
  private
    FTabOnEnter: Boolean;
    FAutoOpen: boolean;
  protected
    procedure DoEnter; override;
    procedure KeyPress(var Key: Char); override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  public
    constructor Create(AOwner: TComponent); override;
  published
    property AutoOpen: boolean read FAutoOpen write FAutoOpen;
    property TabOnEnter: Boolean read FTabOnEnter write FTabOnEnter;
  end;
{$ENDREGION}

{$REGION 'TRailsDate'}
  TRailsDate = class(TPanel)
  private
    edtDay, edtYear: TRailsEdit;
    cmbMonth: TRailsComboBox;
    Dic: TDictionary<Integer,String>;
    FValue: TDateTime;
    FTabOnEnter: Boolean;
    procedure SetAsString(const Value: string);
    function GetAsString: string;
    procedure SetValue(const Value: TDateTime);
    procedure cmbMonthKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure cmbMonthKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure cmbMonthExit(Sender: TObject);
    procedure CreateedtDay;
    procedure CreatecmbMonth;
    procedure CreateedtYear;
    procedure edtYearKeyDown(Sender: TObject; var Key: char);
    procedure cmbMonthChange(Sender: TObject);
    procedure edtDayChange(Sender: TObject);
    procedure cmbMonthCloseUp(Sender: TObject);
  protected
    procedure SetParent(AParent: TWinControl); override;
    procedure SetName(const Value: TComponentName); override;
  public
    constructor Create(AOwner: TComponent); override;
    procedure DoExit; override;
    destructor Destroy; override;
    property AsString: string read GetAsString write SetAsString;
    property AsDate: TDateTime read FValue write SetValue;
  published
    property TabOnEnter: Boolean read FTabOnEnter write FTabOnEnter;
  end;
{$ENDREGION}

{$REGION 'TRailsTime'}
  TRailsTime = class(TPanel)
  private
    edtHour, edtMinutes, edtSeconds: TRailsEdit;
    FValue: TDateTime;
    FTabOnEnter: Boolean;
    function GetAsString: string;
    procedure SetAsString(const Value: string);
    procedure SetValue(const Value: TDateTime);
    procedure CreateedtHour;
    procedure CreateedtMinutes;
    procedure CreateedtSeconds;
    procedure EdtsKeyPress(Sender: TObject; var Key: Char);
    procedure EdtsEnter(Sender: TObject);
    procedure EdtHourChange(Sender: TObject);
    procedure EdtMinuteSecondChange(Sender: TObject);
  protected
    procedure SetParent(AParent: TWinControl); override;
    procedure SetName(const Value: TComponentName); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    property AsString: string read GetAsString write SetAsString;
    property AsTime: TDateTime read FValue write SetValue;
  published
    property TabOnEnter: Boolean read FTabOnEnter write FTabOnEnter;
  end;
{$ENDREGION}

{$REGION 'TRailsDateTime'}
  TRailsDateTime = class(TPanel)
  private
    RdtDate: TRailsDate;
    RtmTime: TRailsTime;
    FValue: TDateTime;
    FTabOnEnter: Boolean;
    function GetAsString: string;
    procedure SetAsString(const Value: string);
    procedure SetValue(const Value: TDateTime);
    procedure setTabOnEnter(const Value: Boolean);
  protected
    procedure SetParent(AParent: TWinControl); override;
    procedure SetName(const Value: TComponentName); override;
  public
    constructor Create(AOwner: TComponent); override;
    property AsString: string read GetAsString write SetAsString;
    property AsDateTime: TDateTime read FValue write SetValue;
  published
    property TabOnEnter: Boolean read FTabOnEnter write setTabOnEnter;
  end;
{$ENDREGION}

procedure register;

implementation

uses
  RTTI, TypInfo, System.DateUtils, System.SysUtils, Rails.Consts,
  WinApi.Windows, Winapi.Messages, Rails.Vcl.Utils, Vcl.Forms, System.Math,
  Rails.View.Settings, Vcl.Graphics;

procedure register;
begin
  RegisterComponents('RailsComponets', [TRailsEdit, TRailsComboBox, TRailsDate, TRailsTime, TRailsDateTime]);
end;

{$REGION 'TValidatesEventsRails'}
{ TValidatesEventsRails }

class procedure TValidatesEventsRails.Bank_Change(Sender: TObject; Precision, Decimals:Integer; Validation: TRailsValidations);
begin
  if ((LocalSettings.InputBank = ibMoney) and (rvMoney in Validation)) or (LocalSettings.InputBank = ibAll) then
    inherited Bank_Change(Sender, (rvMoney in Validation), Precision, Decimals);
end;

class procedure TValidatesEventsRails.Bank_KeyPress(Sender: TObject;
  var Key: Char; Precision: Integer; Validation: TRailsValidations);
begin
  if ((LocalSettings.InputBank = ibMoney) and (rvMoney in Validation)) or (LocalSettings.InputBank = ibAll) then
    inherited Bank_KeyPress(Sender, Key, Precision);
end;

class procedure TValidatesEventsRails.Bank_KeyUp(Sender: TObject; Validation: TRailsValidations);
begin
  if ((LocalSettings.InputBank = ibMoney) and (rvMoney in Validation)) or (LocalSettings.InputBank = ibAll) then
    inherited Bank_KeyUp(Sender);
end;

class procedure TValidatesEventsRails.LoadSettingsCharCase(Sender: TObject);
var
  Ctx: TRttiContext;
  Typ: TRttiType;
  Prop: TRttiProperty;
begin
  Ctx := TRttiContext.Create;
  Typ := Ctx.GetType(Sender.ClassType);
  Prop := Typ.GetProperty('CharCase');
  if LocalSettings.UpperCase in [rcLower, rcNormal, rcUpper] then
    Prop.SetValue(Sender, TValue.FromOrdinal(Prop.PropertyType.Handle, Integer(LocalSettings.UpperCase)));
end;

class procedure TValidatesEventsRails.Money_Enter(Sender: TObject; Validation: TRailsValidations);
begin
  if not (LocalSettings.InputBank in [ibAll, ibMoney]) and (rvMoney in Validation) then
    inherited Money_Enter(Sender);
end;

class procedure TValidatesEventsRails.Money_Exit(Sender: TObject; Validation: TRailsValidations;
 Precision, Decimals:Integer; ShowCurrency: Boolean);
begin
  inherited Money_Exit(Sender, Precision, Decimals, (rvMoney in Validation));
end;

class procedure TValidatesEventsRails.Money_KeyPress(Sender: TObject; var Key: Char; SelText: string; Precision, Decimals:Integer; Validation: TRailsValidations);
begin
  if not (LocalSettings.InputBank in [ibAll, ibMoney]) then
    inherited Money_KeyPress(Sender, Key, SelText, Precision, Decimals);
end;

class procedure TValidatesEventsRails.Positive_Exit(Sender: TObject;
  Validation: TRailsValidations);
begin
{$Message Warn 'Validar Positivo e Negativo'}
end;

class procedure TValidatesEventsRails.TabOnEnter_KeyPress(Sender: TObject;
  var Key: Char);
var
  Ctx: TRttiContext;
  Typ: TrttiType;
  Prop: TRttiProperty;
begin
  Ctx := TRttiContext.Create;
  Typ := Ctx.GetType(Sender.ClassType);
  Prop := Typ.GetProperty('TabOnEnter');
  if Prop.GetValue(Sender).AsBoolean then
    inherited TabOnEnter_KeyPress(Sender, Key);
end;
{$ENDREGION}

{$REGION 'TRailsEdit'}
{ TRailsEdit }

procedure TRailsEdit.Change;
begin
  inherited;
  TValidatesEventsRails.Bank_Change(Self, Precision, Decimals, FValidations);
  if (MaxLength > 0) and (Length(Text) = MaxLength) then
    TRailsUtilsVcl.NextComponent(Self);
end;

constructor TRailsEdit.Create(AOwner: TComponent);
begin
  inherited;
  FTabOnEnter := True;
  TValidatesEventsRails.LoadSettingsCharCase(Self);
end;

destructor TRailsEdit.Destroy;
begin
  inherited;
end;

procedure TRailsEdit.DoEnter;
begin
  inherited;
  if isDecimal then
    TValidatesEventsRails.Money_Enter(Self, FValidations);
  PassWord_Enter;
end;

procedure TRailsEdit.DoExit;
begin
  inherited;
  if isDecimal then
    TValidatesEventsRails.Money_Exit(Self, FValidations, Precision, Decimals);
  TValidatesEventsRails.Positive_Exit(Self, FValidations);
  PassWord_Exit;
end;

procedure TRailsEdit.KeyPress(var Key: Char);
begin
  inherited;
  TValidatesEventsRails.TabOnEnter_KeyPress(Self, Key);
  if isDecimal then
  begin
    TValidatesEventsRails.Bank_KeyPress(Self, Key, Precision, FValidations);
    TValidatesEventsRails.Money_KeyPress(Self, Key, SelText, Precision, Decimals, FValidations);
  end;
end;

procedure TRailsEdit.KeyUp(var Key: Word; Shift: TShiftState);
begin
  inherited;
  if isDecimal then
    TValidatesEventsRails.Bank_KeyUp(Self, FValidations);
end;

procedure TRailsEdit.PassWord_Enter;
begin
  OldText := Text;
end;

procedure TRailsEdit.PassWord_Exit;
begin
  if rvPassWord in FValidations then
  begin
    if OldText <> Text then
    begin
      if LabelTitle <> nil then
      begin
        OldCaption := LabelTitle.Caption;
        LabelTitle.Caption := 'Confirme a Senha';
        if LabelTitle is TLabel then
          TLabel(LabelTitle).Font.Color := clRed;
        OldText := Text;
        SetFocus;
      end;
    end
    else
    begin
      OldText := EmptyStr;
      if OldCaption <> EmptyStr then
      begin
        LabelTitle.Caption := OldCaption;
        OldCaption := EmptyStr;
        if LabelTitle is TLabel then
          TLabel(LabelTitle).Font.Color := clBlack;
      end;
    end;
  end;
end;

procedure TRailsEdit.setIsDecimal(const Value: Boolean);
begin
  FIsDecimal := Value;
  if FisDecimal then
  begin
    Alignment := taRightJustify;
    MaxLength := 0;
  end;
end;

procedure TRailsEdit.setLabelTitle(const Value: TCustomLabel);
begin
  FLabelTitle := Value;
end;

procedure TRailsEdit.SetValidations(const Value: TRailsValidations);
begin
  FValidations := Value;
  if rvPassWord in FValidations then
    PasswordChar := '*'
  else
    PasswordChar := #0;
end;
{$ENDREGION}

{$REGION 'TRailsComboBox'}
{ TRailsComboBox }

constructor TRailsComboBox.Create(AOwner: TComponent);
begin
  inherited;
  FTabOnEnter := True;
end;

procedure TRailsComboBox.DoEnter;
begin
  inherited;
  DroppedDown := FAutoOpen;
end;

procedure TRailsComboBox.KeyDown(var Key: Word; Shift: TShiftState);
begin
  inherited;
  if (ssCtrl in Shift) and (Key = VK_DELETE) then
    ItemIndex := -1;

  if Key = VK_NEXT then
    DroppedDown := True;
end;

procedure TRailsComboBox.KeyPress(var Key: Char);
begin
  inherited;
  TValidatesEventsRails.TabOnEnter_KeyPress(Self, Key);
end;
{$ENDREGION}

{$REGION 'TRailsDate'}
{ TRailsDate }

procedure TRailsDate.cmbMonthCloseUp(Sender: TObject);
begin
  cmbMonth.Style := TComboBoxStyle.csSimple;
  cmbMonth.Top := 0;
  cmbMonth.Height := 17;
end;

procedure TRailsDate.cmbMonthChange(Sender: TObject);
var
  Value: Integer;
begin
  if TryStrToInt(cmbMonth.Text, Value) and (Value > 12) or (cmbMonth.Text = '00') then
  begin
    cmbMonth.Text := cmbMonth.Text[1];
    cmbMonth.SelStart := 2
  end;
  if (Length(cmbMonth.Text) = 2) and (Value > 0) then
    TRailsUtilsVcl.NextComponent(Sender);
end;

procedure TRailsDate.edtDayChange(Sender: TObject);
begin
  if (edtDay.Text <> EmptyStr) and (StrToInt(edtDay.Text) > 31) then
  begin
    edtDay.Text := edtDay.Text[1];
    edtDay.SelStart := 2
  end;
end;

procedure TRailsDate.edtYearKeyDown(Sender: TObject; var Key: Char);
begin
  if (Key = #13) and (Length(edtYear.Text) = 2) then
  begin
    edtYear.Text := Copy(IntToStr(YearOf(Date)), 0, 2)+edtYear.Text;
    Key := #0;
  end;
end;

constructor TRailsDate.Create(AOwner: TComponent);
begin
  inherited;
  Width := 144;
  Height := 19;
  BevelOuter := TBevelCut.bvLowered;
  BevelInner := TBevelCut.bvRaised;
end;

procedure TRailsDate.CreatecmbMonth;
var
  I: Integer;
begin
  cmbMonth := TRailsComboBox.Create(Self);
  cmbMonth.Style := TComboBoxStyle.csSimple;
  cmbMonth.Left := edtDay.Width+4;
  cmbMonth.Top := 0;
  cmbMonth.Width := Self.Width-(edtYear.Width+edtDay.Width+8);
  cmbMonth.Height := 17;
  cmbMonth.Parent := Self;
  cmbMonth.DropDownCount := 12;
  cmbMonth.Name := 'cmbMonth';
  cmbMonth.Text := '';
  cmbMonth.TabOrder := 1;
  Dic := TDictionary<Integer,String>.Create(12);
  for I := Low(Months.Month) to High(Months.Month) do
  begin
    cmbMonth.Items.Add(Months.Month[I]);
    Dic.Add(I+1, UpperCase(Months.Month[I]));
  end;
  cmbMonth.OnExit := cmbMonthExit;
  cmbMonth.OnKeyUp := cmbMonthKeyUp;
  cmbMonth.OnKeyDown := cmbMonthKeyDown;
  cmbMonth.OnChange := cmbMonthChange;
  cmbMonth.OnCloseUp := cmbMonthCloseUp;
end;

procedure TRailsDate.CreateedtDay;
begin
  edtDay := TRailsEdit.Create(Self);
  edtDay.Align := TAlign.alLeft;
  edtDay.Alignment := taCenter;
  edtDay.NumbersOnly := True;
  edtDay.MaxLength := 2;
  edtDay.Width := 21;
  edtDay.Parent := Self;
  edtDay.Name := 'edtDay';
  edtDay.Text := '';
  edtDay.BorderStyle := bsNone;
  edtDay.OnChange := edtDayChange;
end;

procedure TRailsDate.CreateedtYear;
begin
  edtYear := TRailsEdit.Create(Self);
  edtYear.Align := TAlign.alRight;
  edtYear.Alignment := taCenter;
  edtYear.NumbersOnly := True;
  edtYear.MaxLength := 4;
  edtYear.Width := 30;
  edtYear.Parent := Self;
  edtYear.Name := 'edtYear';
  edtYear.Text := '';
  edtYear.BorderStyle := bsNone;
  edtYear.OnKeyPress := edtYearKeyDown;
end;

procedure TRailsDate.cmbMonthExit(Sender: TObject);
var
  I: Integer;
begin
  if TryStrToInt(cmbMonth.Text, I) then
    cmbMonth.ItemIndex := I-1;
end;

procedure TRailsDate.cmbMonthKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if (Key in [VK_NEXT]) then
  begin
    cmbMonth.Style := TComboBoxStyle.csDropDown;
    cmbMonth.Top := -1;
  end;
  if (Key in [VK_RETURN]) and (cmbMonth.DroppedDown) then
    cmbMonth.DroppedDown := False;
end;

procedure TRailsDate.cmbMonthKeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
var
  I: Integer;
begin
  if (Sender <> cmbMonth) or (Key in [VK_BACK, VK_TAB, VK_SHIFT, VK_RETURN]) then
    exit;

  if not (Key in [VK_NUMPAD0..VK_NUMPAD9]) then
  begin
    if Dic.ContainsValue(UpperCase(cmbMonth.Text)) then
      cmbMonth.MaxLength := Length(cmbMonth.Text)
    else
      cmbMonth.MaxLength := 9;

    if (UpperCase(cmbMonth.Text) <> 'JANEIRO') and (Pos(cmbMonth.Items.LineBreak+UpperCase(cmbMonth.Text), UpperCase(cmbMonth.Items.Text)) = 0) then
    begin
      cmbMonth.Text := Copy(cmbMonth.Text, 0, Length(cmbMonth.Text)-1);
      cmbMonth.SelStart := Length(cmbMonth.Text);
    end;
  end else
  begin
    if TryStrToInt(cmbMonth.Text, I) then
    begin
      if (I > 12) then
        cmbMonth.Text := Copy(cmbMonth.Text, 0, Length(cmbMonth.Text)-1);
      cmbMonth.SelStart := Length(cmbMonth.Text);
    end;
  end;
end;

destructor TRailsDate.Destroy;
begin
  FreeAndNil(Dic);
  inherited;
end;

procedure TRailsDate.DoExit;
begin
  if TRailsUtilsVcl.IsDateValid(AsString) then
    inherited;
end;

function TRailsDate.GetAsString: string;
begin
  Result := DateToStr(FValue);
end;

procedure TRailsDate.SetAsString(const Value: string);
begin
  if TryStrToDate(Value, FValue) then
  begin
    edtDay.Text := IntToStr(DayOf(AsDate));
    cmbMonth.ItemIndex := MonthOf(AsDate);
    edtYear.Text := IntToStr(YearOf(AsDate));
  end
  else
    TRailsUtilsVcl.Reject(DATEINVALID);
end;

procedure TRailsDate.SetName(const Value: TComponentName);
begin
  inherited;
  Caption := '';
end;

procedure TRailsDate.SetParent(AParent: TWinControl);
begin
  inherited;
  if edtDay = nil then
  begin
    CreateedtDay;
    CreateedtYear;
    CreatecmbMonth;
  end;
end;

procedure TRailsDate.SetValue(const Value: TDateTime);
begin
  FValue := DateOf(Value);
  edtDay.Text := IntToStr(DayOf(AsDate));
  cmbMonth.ItemIndex := MonthOf(AsDate);
  edtYear.Text := IntToStr(YearOf(AsDate));
end;
{$ENDREGION}

{$REGION 'TRailsTime'}
{ TRailsTime }

constructor TRailsTime.Create(AOwner: TComponent);
begin
  inherited;
  Width := 63;
  Height := 19;
  BevelOuter := TBevelCut.bvLowered;
  BevelInner := TBevelCut.bvRaised;
end;

procedure TRailsTime.EdtHourChange(Sender: TObject);
begin
  if (Length(edtHour.Text) = 1) and (edtHour.Text > '2') then
  begin
    edtHour.Text := '';
    System.SysUtils.Beep;
  end
  else if (Length(edtHour.Text) = 2) and (edtHour.Text > '23') then
  begin
    edtHour.Text := '2';
    System.SysUtils.Beep;
  end;
  edtHour.SelStart := 2;
end;

procedure TRailsTime.EdtMinuteSecondChange(Sender: TObject);
begin
  if (Length(TEdit(Sender).Text) = 1) and (TEdit(Sender).Text > '5') then
  begin
    TEdit(Sender).Text := '';
    System.SysUtils.Beep;
    TEdit(Sender).SelStart := 1;
  end;
end;

procedure TRailsTime.EdtsEnter(Sender: TObject);
begin
  if Sender = edtMinutes then
  begin
    if edtHour.Text = EmptyStr then
      edtHour.SetFocus;
  end;
  if Sender = edtSeconds then
  begin
    if edtHour.Text = EmptyStr then
      edtHour.SetFocus
    else if edtMinutes.Text = EmptyStr then
      edtMinutes.SetFocus;
  end;
end;

procedure TRailsTime.EdtsKeyPress(Sender: TObject; var Key: Char);
begin
  if (Key = #8) and (TCustomEdit(Sender).Text = EmptyStr) then
  begin
    if Sender = edtMinutes then
      edtHour.SetFocus
    else if Sender = edtSeconds then
      edtMinutes.SetFocus;
  end;
end;

procedure TRailsTime.CreateedtHour;
begin
  edtHour := TRailsEdit.Create(nil);
  edtHour.Parent := Self;
  edtHour.MaxLength := 2;
  edtHour.OnChange := EdtHourChange;
  edtHour.Width := 21;
  edtHour.Align := TAlign.alLeft;
  edtHour.BorderStyle := bsNone;
  edtHour.Alignment := taCenter;
  edtHour.OnKeyPress := EdtsKeyPress;
end;

procedure TRailsTime.CreateedtMinutes;
begin
  edtMinutes := TRailsEdit.Create(nil);
  edtMinutes.Parent := Self;
  edtMinutes.MaxLength := 2;
  edtMinutes.OnChange := EdtMinuteSecondChange;
  edtMinutes.Align := TAlign.alClient;
  edtMinutes.BorderStyle := bsNone;
  edtMinutes.Alignment := taCenter;
  edtMinutes.OnEnter := EdtsEnter;
  edtMinutes.OnKeyPress := EdtsKeyPress;
end;

procedure TRailsTime.CreateedtSeconds;
begin
  edtSeconds := TRailsEdit.Create(nil);
  edtSeconds.Parent := Self;
  edtSeconds.MaxLength := 2;
  edtSeconds.OnChange := EdtMinuteSecondChange;
  edtSeconds.Width := 21;
  edtSeconds.Align := TAlign.alRight;
  edtSeconds.BorderStyle := bsNone;
  edtSeconds.Alignment := taCenter;
  edtSeconds.OnEnter := EdtsEnter;
  edtSeconds.OnKeyPress := EdtsKeyPress;
end;

destructor TRailsTime.Destroy;
begin
  inherited;
end;

function TRailsTime.GetAsString: string;
begin
  Result := TimeToStr(FValue);
end;

procedure TRailsTime.SetAsString(const Value: string);
begin
  if TryStrToDate(Value, FValue) then
  begin
    edtHour.Text    := IntToStr(HourOf(AsTime));
    edtMinutes.Text := IntToStr(MinuteOf(AsTime));
    edtSeconds.Text := IntToStr(SecondOf(AsTime));
  end
  else
    TRailsUtilsVcl.Reject(DATEINVALID);
end;

procedure TRailsTime.SetName(const Value: TComponentName);
begin
  inherited;
  Caption := '';
end;

procedure TRailsTime.SetParent(AParent: TWinControl);
begin
  inherited;
  if edtHour = nil then
  begin
    CreateedtHour;
    CreateedtMinutes;
    CreateedtSeconds;
  end;
end;

procedure TRailsTime.SetValue(const Value: TDateTime);
begin
  FValue := Value;
  edtHour.Text    := IntToStr(HourOf(Value));
  edtMinutes.Text := IntToStr(MinuteOf(Value));
  edtSeconds.Text := IntToStr(SecondOf(Value));
end;
{$ENDREGION}

{$REGION 'TRailsDateTime'}
{ TRailsDateTime }

constructor TRailsDateTime.Create(AOwner: TComponent);
begin
  inherited;
  Width := 214;
  Height := 21;
  BevelOuter := TBevelCut.bvNone;
end;

function TRailsDateTime.GetAsString: string;
begin
  Result := RdtDate.AsString+' '+RtmTime.AsString;
end;

procedure TRailsDateTime.SetAsString(const Value: string);
begin
  RdtDate.AsString := Value;
  RtmTime.AsString := Value;
end;

procedure TRailsDateTime.SetName(const Value: TComponentName);
begin
  inherited;
  Caption := '';
end;

procedure TRailsDateTime.SetParent(AParent: TWinControl);
begin
  inherited;
  if (RdtDate = nil) then
  begin
    RdtDate := TRailsDate.Create(Self);
    RdtDate.Parent := Self;
    RdtDate.Align := alLeft;
    RtmTime := TRailsTime.Create(Self);
    RtmTime.Parent := Self;
    RtmTime.Left := RdtDate.Width+4;
    TabOnEnter := True;
  end;
end;

procedure TRailsDateTime.setTabOnEnter(const Value: Boolean);
begin
  FTabOnEnter := Value;
  RdtDate.TabOnEnter := Value;
  RtmTime.TabOnEnter := Value;
end;

procedure TRailsDateTime.SetValue(const Value: TDateTime);
begin
  RdtDate.AsDate := DateOf(Value);
  RtmTime.AsTime := TimeOf(Value);
end;
{$ENDREGION}

end.
